package cn.knightzz.filter;

import cn.hutool.core.util.StrUtil;
import cn.knightzz.util.JwtUtils;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author knightzz
 * @date 2021/4/10 21:32
 */
@Slf4j
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {


    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        // 解决预请求的问题
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        // 处理预请求
        response.setHeader("Access-Control-Allow-Headers", "Authorization,content-type");
        // 不能直接设置为 * 会把 logou请求拦截
        // response.setHeader("Access-Control-Allow-Headers", "*");
        if (request.getMethod().equals("OPTIONS")) {
            log.debug("这是 MyInterceptor OPTIONS 方法");
            response.setStatus(HttpStatus.OK.value());
            response.getWriter().write("OPTIONS returns OK");
            return;
        }
        log.debug("JwtAuthenticationFilter......................");
        // 从请求头中获取token
        String token = request.getHeader("Authorization");
        UsernamePasswordAuthenticationToken authentication = getAuthentication(token, response);
        if (authentication != null) {
            // UsernamePasswordAuthenticationToken 继承 AbstractAuthenticationToken 实现 Authentication
            // 所以当在页面中输入用户名和密码之后首先会进入到 UsernamePasswordAuthenticationToken验证
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        // token为空的情况
        chain.doFilter(request, response);
    }

    /**
     * 根据token解析出相应的权限和用户名
     *
     * @param token
     * @param response
     * @return
     */
    private UsernamePasswordAuthenticationToken getAuthentication(String token, HttpServletResponse response) {

        // 权限
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 解析token
        // 1. 验证token
        if (!StrUtil.isBlank(token)) {
            JwtUtils.verify(token);
            DecodedJWT decodedJWT = JwtUtils.getToken(token);
            // 从token中解析出数据
            String username = decodedJWT.getClaim("username").asString();
            String roleCode = decodedJWT.getClaim("roleCode").asString();
            // 根据角色id查询对应角色
            // 封装角色权限对象
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(roleCode);
            authorities.add(authority);
            // 根据用户id查询对应的用户
            // 封装数据
            User principal = new User(username, "", authorities);
            return new UsernamePasswordAuthenticationToken(principal, token, authorities);
        }
        return null;
    }
}
